home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiniExamples
/
AppKit
/
ZooView
/
SideSplitView.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
6KB
|
245 lines
/*
* SideSplitView.m
*
* Purpose:
* This object implements a split view which divides a view into two
* side by side areas. These areas are intended to be filled by subviews.
* The user can then change the porportion of the subviews to one
* another. The purpose is to provide developers with an alternative to
* NXSplitView.
*
* You may freely copy, distribute, and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied, as to its
* fitness for any particular use.
*
* Written by: Mary McNabb
* Created: Apr 91
*
*/
#import "SideSplitView.h"
#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>
#import <math.h>
#import <libc.h>
#define eventMask NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK
#define DIVIDERWIDTH 8.0 /* the divider is 8 pixels wide. */
#define HALFWIDTH 4.0
static NXRect dimpleRect = {{3.0, 5.0}, {8.0, 7.0}};
/* Retrace is 1/67 of sec * 10^6 micro secs per second */
#define RETRACE (1000000.0/67.0) /* vertical retrace period in micro secs */
@implementation SideSplitView
/*
* initialize the split view. also initialize the size of the divider
*/
- initFrame:(NXRect *) theRect
{
NXSize dimpleSize;
srandom(time(0)); /* initialize random number generator */
[super initFrame:theRect];
[self setAutoresizeSubviews:YES];
dimple = [NXImage findImageNamed:"Dimple"];
[dimple getSize:&dimpleSize];
dimpleHalfHeight = floor(dimpleSize.height / 2.0);
dividerRect.origin.x = 0.0;
dividerRect.origin.y = bounds.origin.y;
dividerRect.size.height = bounds.size.height;
dividerRect.size.width = dimpleSize.width + 3.0;
minX = 0.0;
return self;
}
/*
* initialize the subviews of the split view.
*/
- initViews
{
[window disableFlushWindow];
[self adjustSubviews]; /* just in case we were sloppy in IB */
[window reenableFlushWindow];
[window flushWindow];
[self display];
return self;
}
/*
* take advantage of IB. Use these set methods to initialize the subviews
*/
- setLeftView:(id)newView
{
NXRect leftViewFrame;
leftView = newView;
[leftView setAutosizing:NX_WIDTHSIZABLE|
NX_HEIGHTSIZABLE|NX_MAXXMARGINSIZABLE];
[leftView getFrame:&leftViewFrame];
dividerRect.origin.x = leftViewFrame.size.width;
[self addSubview:leftView];
return self;
}
/*
* don't bother with the size and origin of the view as it gets completely reset in
* adjustSubviews
*/
- setRightView:(id)newView
{
rightView = newView;
[rightView setAutosizing:NX_WIDTHSIZABLE|
NX_HEIGHTSIZABLE|NX_MINXMARGINSIZABLE];
[self addSubview:rightView];
return self;
}
- (BOOL)acceptsFirstMouse
{
return YES;
}
/*
* The side split view consists of a light gray background, and a dimple.
* Relies on the subviews to draw bevels, etc.
*/
- drawSelf:(const NXRect *)r :(int)c
{
NXPoint dimplePoint;
PSsetgray(NX_LTGRAY);
NXRectFill(&bounds);
dimplePoint.x = dividerRect.origin.x + 1.0;
dimplePoint.y = floor(dividerRect.origin.y +
dividerRect.size.height / 2.0 - dimpleHalfHeight);
[dimple composite:NX_SOVER toPoint:&dimplePoint];
return self;
}
/*
* Controls the movement of the divider as the user slides it with the mouse
*/
- mouseDown:(NXEvent *) theEvent
{
NXPoint localPoint = theEvent->location;
NXEvent *nextEvent;
NXCoord lastX=0.0;
int oldMask;
[self convertPoint:&localPoint fromView:nil];
if (!NXMouseInRect(&localPoint, ÷rRect, NO))
return self;
oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
/* We've gotten a mouse down on the divider, so go ahead and draw the slider now */
[self lockFocus];
PSsetinstance(YES);
PSsetgray(.50);
PSsetalpha(0.3333);
PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y,
DIVIDERWIDTH, dividerRect.size.height, NX_COPY);
/* while the user is dragging composite a new slider in new postion -- watching for
* boundary conditions. Exit loop on mouse up.
*/
do {
nextEvent = [NXApp getNextEvent:eventMask];
localPoint = nextEvent->location;
[self convertPoint:&localPoint fromView:nil];
if (localPoint.x < minX) localPoint.x = minX;
if (localPoint.x > maxX) localPoint.x = maxX;
if (localPoint.x != lastX) {
/* wait some random amount of time within retrace period. */
usleep((random() % (int)RETRACE));
PSnewinstance();
PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y,
DIVIDERWIDTH, dividerRect.size.height, NX_COPY);
lastX = localPoint.x;
}
} while (nextEvent->type != NX_MOUSEUP);
/* User is done dragging. Move the divider to new location
*/
dividerRect.origin.x = localPoint.x - HALFWIDTH;
PSsetinstance(NO);
[self unlockFocus];
[self adjustSubviews];
[self display];
[window setEventMask:oldMask];
return self;
}
/*
* blits the dimple to the screen in the right spot
*/
- drawDimple
{
NXPoint origin;
origin.x = dividerRect.origin.x;
origin.y = floor(dividerRect.origin.y + dividerRect.size.height/2.0 - dimpleRect.size.height/2.0);
[dimple composite:NX_COPY fromRect:&dimpleRect toPoint:&origin];
return self;
}
/*
* modifies the size of the subviews after user has positioned the divider, or
* has resized the window.
* also used to initialize the sizes of the subviews.
*/
- adjustSubviews
{
NXRect leftViewFrame, rightViewFrame;
/* first the left one */
[leftView getFrame:&leftViewFrame];
leftViewFrame.size.width = dividerRect.origin.x - leftViewFrame.origin.x;
leftViewFrame.size.height = bounds.size.height;
leftViewFrame.origin.x = bounds.origin.x;
leftViewFrame.origin.y = bounds.origin.y;
[leftView setFrame:&leftViewFrame];
[window invalidateCursorRectsForView:leftView];
/* then the right one */
[rightView getFrame:&rightViewFrame];
rightViewFrame.origin.x = leftViewFrame.size.width + DIVIDERWIDTH;
rightViewFrame.origin.y = bounds.origin.y;
rightViewFrame.size.width = bounds.size.width - rightViewFrame.origin.x;
rightViewFrame.size.height = bounds.size.height;
[rightView setFrame:&rightViewFrame];
[window invalidateCursorRectsForView:rightView];
/* update dividerRect in case of resize of window */
dividerRect.origin.x = leftViewFrame.size.width;
dividerRect.size.height = leftViewFrame.size.height;
dividerRect.origin.y = leftViewFrame.origin.y;
maxX = bounds.size.width - HALFWIDTH;
return self;
}
/*
* called when the window gets resized
*/
- resizeSubviews:(const NXSize *)oldSize
{
[super resizeSubviews:oldSize];
[self adjustSubviews];
return self;
}
@end